﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Globalization;
using System.IO;

namespace Bamboo.Utils
{
    /// <summary>
    /// 运行时编译器封装，简化一下编译器相关类的用法
    /// </summary>
    public class NetCompiler
    {
        public List<string> LibSearchPaths = new List<string>();
        /// <summary>
        /// 源代码文件列表
        /// </summary>
        public List<string> SrcFiles = new List<string>();

        /// <summary>
        /// 编译参数
        /// </summary>
        public CompilerParameters Param = new CompilerParameters();
        /// <summary>
        /// 编译结果
        /// </summary>
        public CompilerResults Result = null;

        public NetCompiler()
        {
            Param.GenerateExecutable = false;
            Param.GenerateInMemory = true;
            Param.IncludeDebugInformation = true;
        }
        /// <summary>
        /// 编译
        /// </summary>
        /// <param name="throwError"></param>
        public void Compile(bool throwError)
        {
            //var provider_options = new Dictionary<string, string>();
            //provider_options.Add("CompilerVersion", "v4");
            var compiler = CodeDomProvider.CreateProvider("C#");
            var codes = new List<string>();
            this.Result = compiler.CompileAssemblyFromFile(Param, SrcFiles.ToArray());
            if (throwError && Result.Errors.HasErrors)
            {
                var errorMsg = new StringBuilder(8 * 1024);
                foreach (CompilerError item in Result.Errors)
                {
                    errorMsg.AppendLine(item.ToString());
                }
                throw new Exception("编译报错\r\n" + errorMsg.ToString());
            }
        }
        /// <summary>
        /// 新增源代码文件
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="e"></param>
        public void AddSourceCodeFile(string filename)
        {
            SrcFiles.Add(filename);
        }

        public void AddSourceCodeFiles(IEnumerable<string> fileNames)
        {
            SrcFiles.AddRange(fileNames);
        }
        /// <summary>
        /// 新增引用库文件
        /// </summary>
        /// <param name="filename"></param>
        public void AddLibFile(string filename)
        {
            foreach (var item in LibSearchPaths)
            {
                string fullname = Path.Combine(item, filename);
                if (File.Exists(fullname))
                {
                    Param.ReferencedAssemblies.Add(fullname);
                    return;
                }
            }
            Param.ReferencedAssemblies.Add(filename);
        }
        /// <summary>
        /// 从清单文件加载引用库
        /// </summary>
        /// <param name="filename">记录文件清单的文件名</param>
        /// <param name="pathPrefix">路径前缀，可以留空</param>
        public void AddLibFilesFromTxt(string filename, Encoding e)
        {
            var lines = System.IO.File.ReadAllLines(filename, e);
            foreach (var line in lines)
            {
                string item = line.Trim();
                if (string.IsNullOrWhiteSpace(item)) continue;
                AddLibFile(item);
            }
        }
        /// <summary>
        /// 从环境变量中加载引用库清单
        /// </summary>
        /// <param name="envName"></param>
        /// <param name="pathPrefix"></param>
        public void AddLibFilesFromEnv(string envName)
        {
            string customLibs = System.Environment.GetEnvironmentVariable(envName);
            if (string.IsNullOrWhiteSpace(customLibs)) return;
            var customLibArray = customLibs.Trim().Split(';');
            foreach (var part in customLibArray)
            {
                string item = part.Trim();
                if (string.IsNullOrWhiteSpace(item)) continue;
                AddLibFile(item);
            }
        }

        /// <summary>
        /// 从编译结果中创建实例
        /// </summary>
        /// <param name="className"></param>
        /// <returns></returns>
        public object CreateInstance(string className)
        {
            var instance = Result.CompiledAssembly.CreateInstance(className, true,
                BindingFlags.Default, null, null, CultureInfo.CurrentCulture, null);
            return instance;
        }
    }
}
